﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
using NewsClassifierFreshnessMeasurement.Crawl;
using NCTrainingDataScraper;
using System.Web;
using System.Configuration;
using System.Data.SqlClient;

namespace PingBingService
{
    class PingBingOperation
    {
        ResearchDBDataContext researchDB = new ResearchDBDataContext();
        bool flag;
        int a = 0;
        volatile bool isDealingPingBing;
        public void Run()
        {
            string flagFilePath = ConfigurationManager.AppSettings["PingBingServiceFlagFilePath"];
            if (flagFilePath == "")
            {
                return;
            }
            PingBingService.WriteLog("PingBingServiceFlagFilePath="+flagFilePath);
            FileSystemWatcher watcher = new FileSystemWatcher();
            watcher.Path = flagFilePath;
            watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
               | NotifyFilters.FileName | NotifyFilters.DirectoryName;
            watcher.Filter = "flag.txt";
            watcher.Changed += new FileSystemEventHandler(OnChanged);
            watcher.EnableRaisingEvents = true;
            DealPingBing();
            AutoResetEvent ev = new AutoResetEvent(true);
            ev.WaitOne();
        }

        private void OnChanged(object source, FileSystemEventArgs e)
        {
            if (flag == true)
            {
                flag = false;
            }
            else
            {
                flag = true;
            }
            ++a;
            if (e.ChangeType == WatcherChangeTypes.Changed && flag == true)
            {
                PingBingService.WriteLog("Trigger Event.");
                if (isDealingPingBing == false)
                {
                    DealPingBing();
                }
            }
        }
        private bool IsTaskInQueue(int _taskID)
        {
            var taskIDRes = from t in researchDB.tb_taskIDQueues
                            where t.taskID == _taskID
                            select t;
            if (taskIDRes.Count() > 0)
            {
                return true;
            }
            return false;
        }
        public void DealPingBing()
        {
            int connInterval = 1000;
            isDealingPingBing = true;
            while (true)
            {
                try
                {
                    var taskIDRes = from taskID in researchDB.tb_taskIDQueues
                                    select taskID;
                    if (taskIDRes.Count() > 0)
                    {
                        try
                        {
                            int taskID = taskIDRes.First().taskID;
                            var queryRes = from news in researchDB.tb_news
                                           from e in news.tb_experiments
                                           from q in e.tb_experimentsQueries
                                           where e.taskID == taskID
                                           select q;
                            PingBingService.WriteLog("--------------------------------------------------------\n                             Start ping bing, taskID:" + taskID);
                            int queryPingedCount = 0;
                            foreach (var query in queryRes)
                            {
                                int position = -1;
                                try
                                {
                                    position = Crawler(query.query, query.tb_experiment.tb_new.ID);
                                    ++queryPingedCount;
                                }
                                catch (Exception e)
                                {
                                    PingBingService.WriteLog("Crawl query error:" + e.Message);
                                }
                                try
                                {
                                    var tmpQueryRes = from q in researchDB.tb_experimentsQueries
                                                      where q.ID == query.ID
                                                      select q;
                                    if (tmpQueryRes.Count() > 0)
                                    {
                                        tmpQueryRes.First().position = position;
                                    }
                                    researchDB.SubmitChanges();
                                }
                                catch (Exception e)
                                {
                                    PingBingService.WriteLog(e.Message);
                                }
                                if (!IsTaskInQueue(taskID))
                                {
                                    PingBingService.WriteLog("Cancel ping bing, taskID:" + taskID);
                                    break;
                                }
                            }
                            PingBingService.WriteLog("Pinged bing queries' count:" + queryPingedCount);
                            PingBingService.WriteLog("End ping bing, taskID:" + taskID + "\n                             --------------------------------------------------------");
                            var taskIDDelete = from t in researchDB.tb_taskIDQueues
                                               where t.taskID == taskID
                                               select t;
                            if (taskIDDelete.Count() > 0)
                            {
                                researchDB.tb_taskIDQueues.DeleteOnSubmit(taskIDDelete.First());
                            }
                            researchDB.SubmitChanges();
                        }
                        catch (Exception e)
                        {
                            PingBingService.WriteLog(e.Message);
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                catch (Exception e)
                {
                    PingBingService.WriteLog(e.Message);
                    //cannot connect to database. Delay to connect to sql.
                    Thread.Sleep(connInterval);
                    if (connInterval < 10000)
                    {
                        connInterval += 500;
                    }
                }
            }
            isDealingPingBing = false;
        }
        string GetMarket(int newsID)
        {
            var res = from n in researchDB.tb_news
                      where n.ID == newsID
                      select new
                      {
                          market = n.market
                      };
            if (res.Count() > 0)
            {
                return res.First().market;
            }
            return "";
        }
        public string EncodeUrl(string query, int newsID)
        {
            string market = GetMarket(newsID);
            string url = "";
            if (market.ToLower() == "en-us")
            {
                url = "http://origin.co3.bing.com/search?q=" + HttpUtility.UrlEncode(query) + "&form=MONITR&mkt=en-us&setflight=flt9:0&setflight=flt3:0&setflight=flt23:0";
            }
            else if (market.ToLower() == "zh-cn")
            {
                url = "http://origin.bj1.bing.com/search?q=" + HttpUtility.UrlEncode(query) + "&form=MONITR&mkt=zh-cn&setflight=flt9:0&setflight=flt3:0&setflight=flt23:0";
            }
            return url;
        }
        public int Crawler(string query, int newsID)
        {
            Crawler crawler = NewsClassifierFreshnessMeasurement.Crawl.Crawler.CreateCrawler(CrawlerType.Net);
            var result = crawler.Crawl(new CrawlerParam
            {
                Uri = EncodeUrl(query, newsID),
                Proxy = "itgproxy.redmond.corp.microsoft.com",
                UserAgent = CrawlerParam.UserAgent_IE9,
                Timeout = 10000
            });

            ResponseParser parser = ResponseParser.CreateResponseParser(ParserType.Bing);
            NewsAnswerPositionInfo newsAnswerInfo = parser.Parse(result.Content);
            if (newsAnswerInfo != null)
            {
                return newsAnswerInfo.AnswerPosition;
            }
            return -1;
        }
    }
}
